﻿//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//  SchedulerManagerTest.cs
//    
// Abstract:
//
//  Unit tests for the SchedulerManager class.
//  
//--

using System;
using System.Diagnostics;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using TestHelpers = Microsoft.EnhancedReminders.UnitTests.Helpers;

namespace Microsoft.EnhancedReminders.Scheduler.UnitTests
{
    /// <summary>
    /// This is a test class for SchedulerManager and is intended
    /// to contain all SchedulerManager Unit Tests
    /// </summary>
    [TestClass()]
    public class SchedulerManagerTest : IDispatcherProxy
    {
        // Used to notify a test that SendMessage has been invoked by the Scheduler under test
        private static ManualResetEvent _waitEvent;

        // The NotificationItem associated with SendMessage
        private NotificationItem _actualItem;

        // The SchedulerManager instance being tested
        private static SchedulerManager_Accessor _target;

        /// <summary>
        /// Initialize the wait event.
        /// </summary>
        /// <param name="testContext"></param>
        [ClassInitialize()]
        public static void MyClassInitialize(TestContext testContext)
        {
            _waitEvent = new ManualResetEvent(false);
        }
        
        /// <summary>
        /// Cleanup the wait event.
        /// </summary>
        [ClassCleanup()]
        public static void MyClassCleanup()
        {
            if (_waitEvent != null)
            {
                _waitEvent.Close();
            }
        }
        
        /// <summary>
        /// Reset the wait event and create a new SchedulerManager instance for each test.
        /// </summary>
        [TestInitialize()]
        public void MyTestInitialize()
        {
            Debug.Assert(_waitEvent != null, "_waitEvent != null");
            _actualItem = null;
            _waitEvent.Reset();
            _target = new SchedulerManager_Accessor(null /* exchangeUsers */, this);
        }

        /// <summary>
        /// Dispose of the SchedulerManager instance used in the proceeding test.
        /// </summary>
        [TestCleanup()]
        public void MyTestCleanup()
        {
            if (_target != null)
            {
                _target.Dispose();
                _target = null;
            }
        }
        
        /// <summary>
        /// Test that a reminder with the current time is immediately sent to the Dispatcher.
        /// </summary>
        /// <remarks>
        /// The test adds a reminder with the current time to the schedule and verifies that SendNotification is invoked.
        /// </remarks>
        [TestMethod()]
        [DeploymentItem("Microsoft.EnhancedReminders.SchedulerService.exe")]
        public void CurrentReminderSentTest()
        {
            DateTime expectedTime = DateTime.UtcNow;
            NotificationItem expectedItem = TestHelpers.CreateNotificationItem("1", expectedTime);
            _target._schedule.ExchangeUsers_ItemUpdated(null /* sender */, new ItemUpdatedEventArgs_Accessor(expectedItem.Id.Id, new NotificationItem[] { expectedItem }));
            TestHelpers.WaitOne(_waitEvent, "SendNotification not invoked");
            Assert.AreEqual(expectedItem, _actualItem, "Unexpected NotificationItem");
        }

        /// <summary>
        /// Test that a reminder with a time in the past is immediately sent to the Dispatcher.
        /// </summary>
        /// <remarks>
        /// The test adds a reminder with a time in the past to the schedule and verifies that SendNotification is invoked.
        /// </remarks>
        [TestMethod()]
        [DeploymentItem("Microsoft.EnhancedReminders.SchedulerService.exe")]
        public void OldReminderSentTest()
        {
            DateTime expectedTime = DateTime.UtcNow - TimeSpan.FromMinutes(10);
            NotificationItem expectedItem = TestHelpers.CreateNotificationItem("1", expectedTime);
            _target._schedule.ExchangeUsers_ItemUpdated(null /* sender */, new ItemUpdatedEventArgs_Accessor(expectedItem.Id.Id, new NotificationItem[] { expectedItem }));
            TestHelpers.WaitOne(_waitEvent, "SendNotification not invoked");
            Assert.AreEqual(expectedItem, _actualItem, "Unexpected NotificationItem");
        }

        /// <summary>
        /// Test that a reminder with a time in the future is not immediately sent to the Dispatcher.
        /// </summary>
        /// <remarks>
        /// The test adds a reminder with a time in the future to the schedule and verifies that SendNotification is not invoked.
        /// </remarks>
        [TestMethod()]
        [DeploymentItem("Microsoft.EnhancedReminders.SchedulerService.exe")]
        public void FutureReminderNotSentTest()
        {
            DateTime expectedTime = DateTime.UtcNow + TimeSpan.FromMinutes(10);
            NotificationItem expectedItem = TestHelpers.CreateNotificationItem("1", expectedTime);
            _target._schedule.ExchangeUsers_ItemUpdated(null /* sender */, new ItemUpdatedEventArgs_Accessor(expectedItem.Id.Id, new NotificationItem[] { expectedItem }));
            bool signalled = _waitEvent.WaitOne(1000, false);
            Assert.IsFalse(signalled, "SendNotification was unexpectedly invoked");
            Assert.IsNull(_actualItem, "Unexpected NotificationItem");
        }

        /// <summary>
        /// Invoked when the Scheduler under test sends a reminder to the Dispacther.
        /// </summary>
        /// <param name="notificationItem">Reminder being sent</param>
        public void SendNotification(NotificationItem notificationItem)
        {
            _actualItem = notificationItem;
            _waitEvent.Set();
        }
    }
}
